/*
 * =============================================================================
 * "THE BEER-WARE LICENSE" (Revision 42):
 * <eirikb@google.com> wrote this file. As long as you retain this notice you
 * can do whatever you want with this stuff. If we meet some day, and you think
 * this stuff is worth it, you can buy me a beer in return Eirik Brandtzæg
 * =============================================================================
 */
package no.eirikb.robotec.terminal;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Logger;
import no.eirikb.robotec.terminal.element.CommandLine;
import no.eirikb.robotec.terminal.element.CommandBox;
import no.eirikb.robotec.terminal.element.Element;
import no.eirikb.robotec.terminal.element.Less;

/**
 *
 * @author eirikb
 * @author <a href="mailto:eirikb@google.com">eirikb@google.com</a>
 */
public class TerminalFileParser {

    private Terminal terminal;
    private int x;
    private int y;

    private enum CODETYPE {

        UNKNOWN, E, ELEMENT;

        public static CODETYPE getCode(String c) {
            try {
                return CODETYPE.valueOf(c);
            } catch (Exception ex) {
            }
            return UNKNOWN;
        }
    }

    private enum ELEMENTTYPE {

        UNKNOWN, COMMANDBOX, COMMANDLINE, LESS;

        public static ELEMENTTYPE getElement(String e) {
            try {
                return ELEMENTTYPE.valueOf(e);
            } catch (Exception ex) {
            }
            return UNKNOWN;
        }
    }

    public TerminalFileParser(Terminal terminal) {
        this.terminal = terminal;
        x = 1;
        y = 1;
    }

    public void parseFile(String fileName) {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(
                    new FileInputStream(terminal.getFile().getAbsoluteFile() + File.separator + fileName)));
            String line;
            List<String> code = new ArrayList<String>();
            while ((line = reader.readLine()) != null) {
                String text = line;
                String comment = line.trim();
                if (comment.length() == 0 || (comment.charAt(0) != '#')) {
                    int branch = -1;
                    if ((branch = line.indexOf("{{")) >= 0) {
                        x = branch;
                        code.add(line.substring(branch + 2));
                        text = line.substring(0, branch);
                    }

                    if (code.size() > 0) {
                        if (branch < 0) {
                            code.add(line);
                        }
                        if ((branch = code.get(code.size() - 1).indexOf("}}")) >= 0) {
                            code.set(code.size() - 1, code.get(code.size() - 1).substring(0, branch));
                            text = line.substring(line.indexOf("}}") + 2);
                            parseCode(code);
                            code.clear();
                        }
                    } else {
                        y++;
                        terminal.getServer().sendLagText(text + "\r\n");
                    }
                }
            }
            if (terminal.getElements().size() > 0) {
                terminal.setCurrentElement(terminal.getElements().get(0));
            }
        } catch (IOException ex) {
            Logger.getLogger(Terminal.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void parseCode(List<String> code) {
        for (String c : code) {
            StringTokenizer st = new StringTokenizer(c, " ");
            String cmd = st.nextToken();
            switch (CODETYPE.getCode(cmd)) {
                case ELEMENT:
                case E:
                    Element element = null;
                    switch (ELEMENTTYPE.getElement(st.nextToken())) {
                        case COMMANDBOX:
                            try {
                                int width = Integer.parseInt(st.nextToken());
                                int height = Integer.parseInt(st.nextToken());
                                y++;
                                element = new CommandBox(terminal, x, y, width, height);
                            } catch (NumberFormatException ex) {
                                error("Must specify X and Y for element " + c);
                            } catch (NoSuchElementException ex) {
                                error("Must specify X and Y for element " + c);
                            }
                            break;
                        case COMMANDLINE:
                            element = new CommandLine(terminal);
                            break;
                        case LESS:
                            try {
                                int width = Integer.parseInt(st.nextToken());
                                int height = Integer.parseInt(st.nextToken());
                                y++;
                                element = new Less(terminal, x, y, width, height, st.nextToken());
                            } catch (NumberFormatException ex) {
                                error("Must specify X and Y for element " + c);
                            } catch (NoSuchElementException ex) {
                                error("Must specify X and Y for element " + c);
                            }
                            break;
                        case UNKNOWN:
                            terminal.getServer().sendLagText("No such element: " + c);
                            System.out.println("Unknown element: " + c);
                            break;
                    }
                    if (element != null) {
                        terminal.getElements().add(element);
                    }
                    break;
                case UNKNOWN:
                    System.out.println("Unknown code: " + cmd);
                    break;
            }
        }
    }

    private void error(String error) {
        terminal.getServer().sendLagText("ERROR (line " + y + "): " + error + "\r\n");
    }
}